package com.cn.web.menu.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cn.exception.MyException;
import com.cn.menu.ButtonsDO;
import com.cn.menu.MenuDO;
import com.cn.role.RoleMenuDO;
import com.cn.web.menu.controller.MenuController;
import com.cn.web.menu.mapper.IButtonMapper;
import com.cn.web.menu.mapper.IMenuMapper;
import com.cn.web.menu.service.MenuService;
import com.cn.web.menu.vo.MenuVO;
import org.apache.commons.collections.map.LinkedMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * description: MenuService <br>
 * date: 21.12.16 11:13 <br>
 * author: cn_yaojin <br>
 * version: 1.0 <br>
 */
@Service
public class MenuServiceImpl implements MenuService {

    @Autowired
    private IMenuMapper menuMapper;

    @Autowired
    private IButtonMapper buttonMapper;

    private static Map<String /*按钮编号*/, ButtonsDO> button_map = new HashMap<>();

    @Override
    public void reloadButton() {
        List<ButtonsDO> buttons = this.buttonMapper.selectList(null);
        if (buttons != null) {
            buttons.forEach(t -> {
                button_map.put(t.getNo(), t);
            });
        }
    }

    @Override
    public ButtonsDO getButton(String button) {
        if (button_map.size() == 0) {
            reloadButton();
        }
        return button_map.get(button);
    }

    @Override
    public List<MenuVO> listMenuByParentId(String parentId) {
        List<MenuVO> menus = this.menuMapper.listAll();
        if (menus != null) {
            var data = menus.stream().filter(t -> t.getParentNo().equals(parentId)).collect(Collectors.toList());
            if (data != null) {
                for (MenuVO t : data) {
                    t.setChild(MenuController.empty);
                }
            }
            return data;
        }
        return null;
    }

    /**
     * 查询所有菜单
     *
     * @return
     */
    @Override
    public List<MenuVO> listAllMenu() {
        this.reloadButton();
        List<MenuVO> menus = this.menuMapper.listAll();
        List<MenuVO> list = menus.stream().filter(t -> t.getParentNo().equalsIgnoreCase("0")).collect(Collectors.toList());
        return filterAllMenus(list, menus);
    }

    @Override
    public List<MenuVO> listAllMenuSource(Object pd) {
        return this.menuMapper.listAll();
    }

    /**
     * 递归将菜单处理成菜单树，并封装其操作按钮
     *
     * @param list
     * @param parentNo
     * @param level
     * @param buttons  该菜单拥有的按钮
     * @return
     */
    private static List<MenuVO> filterMenu2Tree(List<MenuVO> list, String parentNo, int level, Map<String, Set<String>> buttons) {
        List<MenuVO> data = list.stream().filter(t -> t.getParentNo().equalsIgnoreCase(parentNo)).collect(Collectors.toList());
        List<MenuVO> tmpMenu = new ArrayList<>();
        if (data != null && data.size() > 0) {
            for (MenuVO t : data) {
                t.setLevel(level);
                //处理按钮
                packButton2Menu(t, buttons);
                var tmp = filterMenu2Tree(list, t.getMenuNo(), level + 1, buttons);
                if (tmp != null && tmp.size() > 0) {
                    t.setChild(tmp);
                }
                tmpMenu.add(t);
            }
        }
        return tmpMenu;
    }

    /**
     * 登录人查询自己的菜单
     *
     * @param userId
     * @return
     */
    @Override
    public List<MenuVO> listMenus(String userId) {
        List<MenuVO> menus = this.menuMapper.listAll();
        this.reloadButton();
        //获取顶级菜单
        List<MenuVO> list = menus.stream().filter(t -> t.getParentNo().equalsIgnoreCase("0")).collect(Collectors.toList());
        if (StringUtils.isEmpty(userId)) {
            return filterAllMenus(list, menus);
        } else {
            Map<String, Object> pd = new HashMap<>();
            pd.put("userId", userId);
            List<RoleMenuDO> roles = this.menuMapper.listByRole(pd);
            Map<String  /*菜单编号*/, Set<String>  /*按钮集合*/> buttons = new HashMap<>();
            roles.forEach(t -> {
                Set<String> sets = buttons.get(t.getMenuId());
                if (sets == null) {
                    sets = new LinkedHashSet<>();
                    buttons.put(t.getMenuId(), sets);
                }
                //合并菜单功能按钮权限
                if (StringUtils.isNotEmpty(t.getButtons())) {
                    List<String> button = JSON.parseArray(t.getButtons(), String.class);
                    for (String b : button) {
                        sets.add(b.replaceAll(t.getMenuId() + "_", ""));
                    }
                }
            });

            List<MenuVO> tmpMenus = new ArrayList<>();
            for (MenuVO menu : menus) {
                if (buttons.containsKey(menu.getMenuNo())) {
                    tmpMenus.add(menu);
                }
            }
            List<MenuVO> tmpList = new ArrayList<>();
            for (MenuVO menu : list) {
                if (buttons.containsKey(menu.getMenuNo())) {
                    tmpList.add(menu);
                }
            }

            return packMenu2TreeAndButton(tmpList, tmpMenus, buttons);
        }
    }

    /**
     * @param list  将menus过滤后的数据
     * @param menus 原始菜单数据
     * @return
     */
    public static List<MenuVO> filterAllMenus(List<MenuVO> list, List<MenuVO> menus) {
        Map<String  /*菜单编号*/, Set<String>  /*按钮集合*/> buttons = new LinkedHashMap<>();
        for (MenuVO menuVo : menus) {
            if (StringUtils.isNotEmpty(menuVo.getButtons())) {
                List<String> button = JSON.parseArray(menuVo.getButtons(), String.class);
                Set<String> sets = new LinkedHashSet<>();
                sets.addAll(button);
                buttons.put(menuVo.getMenuNo(), sets);
            }
        }
        return packMenu2TreeAndButton(list, menus, buttons);
    }

    /**
     * 遍历顶级菜单，并处理器子级菜单
     *
     * @param list     将allMenus过滤后的数据
     * @param allMenus 原始菜单数据
     * @param buttons  菜单-按钮集
     * @return
     */
    public static List<MenuVO> packMenu2TreeAndButton(List<MenuVO> list, List<MenuVO> allMenus, Map<String, Set<String>> buttons) {
        Map<String, MenuVO> myMenus = new LinkedMap();
        //遍历该用户拥有的菜单
        for (MenuVO menu : list) {
            packButton2Menu(menu, buttons);
            List<MenuVO> son = new ArrayList<>();
            son = filterMenu2Tree(allMenus, menu.getMenuNo(), 2, buttons);
            MenuVO menuVo = myMenus.get(menu.getMenuNo());
            if (menuVo == null) {
                myMenus.put(menu.getMenuNo(), menu);
                menuVo = menu;
                menuVo.setLevel(1);
            }
            menuVo.setChild(son);
        }
        var tmp_menus = myMenus.values().stream().collect(Collectors.toList());
        return tmp_menus;
    }

    @Override
    public List<RoleMenuDO> listRoleMenus(String roleId) {
        QueryWrapper<RoleMenuDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_id", roleId);
        return null;
    }

    public static void packButton2Menu(MenuVO menu, Map<String  /*菜单编号*/, Set<String>  /*按钮集合*/> buttons) {
        Set<String> btn = buttons.get(menu.getMenuNo());
        if (btn != null && btn.size() > 0) {
            List<ButtonsDO> tmpButtons = new ArrayList<>();
            for (String s : btn) {
                ButtonsDO b = button_map.get(s);
                if (b != null) {
                    tmpButtons.add(
                            new ButtonsDO().setName(b.getName()).setType(b.getType()).setNo(b.getNo())
                    );
                }
            }
            menu.setButtonArray(tmpButtons);
        }
    }

    /**
     * 编辑
     *
     * @param info
     */
    @Override
    public void edit(MenuDO info) {
        if (info.getAppType() == null) {
            info.setAppType(0);
        }
        if (StringUtils.isEmpty(info.getAppName())) {
            info.setAppName("");
        }
        QueryWrapper<MenuDO> search = new QueryWrapper<>();
        search.eq("menu_no", info.getMenuNo());
        if (info.getId() != null && info.getId() > 0) {
            search.ne("id", info.getId());
        }
        long count = this.menuMapper.selectCount(search);
        if (count > 0) {
            throw new MyException("菜单编号：" + info.getMenuNo() + "已存在");
        }

        if (info.getId() == null || info.getId() <= 0) {
            this.menuMapper.insert(info);
        } else {
            this.menuMapper.update(info);
        }
    }


    /**
     * 删除
     *
     * @param id
     */
    @Override
    public void del(String id) {
        var data = this.menuMapper.selectById(id);
        if (data == null) {
            throw new MyException("菜单信息不存在");
        }
        QueryWrapper<MenuDO> search = new QueryWrapper<>();
        search.eq("parent_no", data.getMenuNo());
        long count = this.menuMapper.selectCount(search);
        if (count > 0) {
            throw new MyException("菜单下存在子级，禁止删除");
        }
        this.menuMapper.deleteById(id);
    }

    @Override
    public MenuVO findById(String id) {
        var data = this.menuMapper.selectById(id);
        if (data == null) {
            throw new MyException("菜单信息不存在");
        }
        MenuVO menuVo = new MenuVO();
        BeanUtils.copyProperties(data, menuVo);
        if (StringUtils.isNotEmpty(data.getButtons())) {
            reloadButton();
            List<String> buttons = JSON.parseArray(data.getButtons(), String.class);
            for (String button : buttons) {
                ButtonsDO buttonTmp = button_map.get(button);
                if (buttonTmp != null) {
                    menuVo.getButtonArray().add(buttonTmp);
                }
            }
        }
        return menuVo;
    }

}
